#include "Coder.h"

#include <iostream>
#include <memory>

using namespace rocket::common;
using namespace clang;
using namespace std;

/// setPrintinPolicy - 设置通用的显示策略
static void setPrintinPolicy(clang::PrintingPolicy &pp,
                             const clang::LangOptions &lo) {
  if (lo.CPlusPlus) {
    pp.adjustForCPlusPlus();  // CPP风格的输出
  }
  pp.SuppressUnwrittenScope = true;  // 忽略无名边界
  pp.FullyQualifiedName = true;
}

static void printQualifiedName(const clang::NamedDecl *ND, raw_ostream &OS,
                               const PrintingPolicy &P) {
  const DeclContext *Ctx = ND->getDeclContext();

  // For ObjC methods, look through categories and use the interface as context.
  if (auto *MD = dyn_cast<ObjCMethodDecl>(ND))
    if (auto *ID = MD->getClassInterface()) Ctx = ID;

  if (Ctx->isFunctionOrMethod()) {
    ND->printName(OS);
    return;
  }

  using ContextsTy = SmallVector<const DeclContext *, 8>;
  ContextsTy Contexts;

  // Collect named contexts.
  while (Ctx) {
    if (isa<NamedDecl>(Ctx)) {
      if (auto CXXRD = dyn_cast<CXXRecordDecl>(Ctx)) {
        if (CXXRD->getDeclName().isEmpty()) {
          OS << *ND;
          return;
        }
      }
      Contexts.push_back(Ctx);
    }
    Ctx = Ctx->getParent();
  }

  for (const DeclContext *DC : llvm::reverse(Contexts)) {
    if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
      OS << Spec->getName();
      const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
      printTemplateArgumentList(OS, TemplateArgs.asArray(), P);
    } else if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) {
      if (P.SuppressUnwrittenScope &&
          (ND->isAnonymousNamespace() || ND->isInline()))
        continue;
      if (ND->isAnonymousNamespace()) {
        OS << (P.MSVCFormatting ? "`anonymous namespace\'"
                                : "(anonymous namespace)");
      } else {
        OS << *ND;
      }
    } else if (const auto *RD = dyn_cast<RecordDecl>(DC)) {
      if (!RD->getIdentifier()) {
        if (!RD->isAnonymousStructOrUnion()) {
          auto RD_next = dyn_cast<TypedefDecl>(RD->getNextDeclInContext());
          if (RD_next && RD_next->getAnonDeclWithTypedefName() == RD) {
            OS << RD_next->getNameAsString();
          } else if (P.SuppressUnwrittenScope) {
            continue;
          } else {
            OS << "(anonymous " << RD->getKindName() << ')';
          }
        } else if (P.SuppressUnwrittenScope) {
          continue;
        } else {
          OS << "(anonymous  " << RD->getKindName() << ')';
        }
      } else {
        OS << *RD;
      }
    } else if (const auto *FD = dyn_cast<FunctionDecl>(DC)) {
      const FunctionProtoType *FT = nullptr;
      if (FD->hasWrittenPrototype())
        FT = dyn_cast<FunctionProtoType>(FD->getType()->castAs<FunctionType>());

      OS << *FD << '(';
      if (FT) {
        unsigned NumParams = FD->getNumParams();
        for (unsigned i = 0; i < NumParams; ++i) {
          if (i) OS << ", ";
          OS << FD->getParamDecl(i)->getType().stream(P);
        }

        if (FT->isVariadic()) {
          if (NumParams > 0) OS << ", ";
          OS << "...";
        }
      }
      OS << ')';
    } else if (const auto *ED = dyn_cast<EnumDecl>(DC)) {
      // C++ [dcl.enum]p10: Each enum-name and each unscoped
      // enumerator is declared in the scope that immediately contains
      // the enum-specifier. Each scoped enumerator is declared in the
      // scope of the enumeration.
      // For the case of unscoped enumerator, do not include in the qualified
      // name any information about its enum enclosing scope, as its visibility
      // is global.
      if (ED->isScoped())
        OS << *ED;
      else
        continue;
    } else {
      OS << *cast<NamedDecl>(DC);
    }
    OS << "::";
  }

  if (ND->getDeclName() || isa<DecompositionDecl>(ND))
    OS << *ND;
  else
    OS << "(anonymous)";
}

/// createPrintinPolicy - 构建显示策略
clang::PrintingPolicy rocket::common::createPrintingPolicy(
    const clang::LangOptions &lo) {
  auto pp = clang::PrintingPolicy(lo);
  setPrintinPolicy(pp, lo);
  return pp;
}
clang::PrintingPolicy rocket::common::createPrintingPolicy(
    const clang::ASTContext &ast) {
  return createPrintingPolicy(ast.getLangOpts());
}

/// getFullNDeclName - 获取有名声明的带边界可用全名或修饰名。
std::string rocket::common::getFullNDeclName(const clang::NamedDecl *nd,
                                             bool mangled) {
  assert(nd);
  std::string name;
  llvm::raw_string_ostream OS(name);
  if (mangled) {
    // 修饰名
    auto &ast = nd->getASTContext();
    std::shared_ptr<clang::MangleContext> mc(
        ItaniumMangleContext::create(ast, ast.getDiagnostics()));
#if LLVM_VERSION_MAJOR >= 11
    // clang 11 后的mangled方式
    // mangleName中对CXXCtorType与CXXDtorType不关心，随意填入
    if (auto cxxctor = dyn_cast<CXXConstructorDecl>(nd))
      mc->mangleName(GlobalDecl(cxxctor, CXXCtorType::Ctor_Base), OS);
    else if (auto cxxdtor = dyn_cast<CXXDestructorDecl>(nd))
      mc->mangleName(GlobalDecl(cxxdtor, CXXDtorType::Dtor_Base), OS);
    else if (auto ftd = dyn_cast<FunctionTemplateDecl>(nd))
      return getFullNDeclName(ftd->getTemplatedDecl(), mangled);
    else
#endif
      mc->mangleName(nd, OS);

  } else {
    // 全名
    /*if (show_anonymous) {
      nd->printQualifiedName(OS, createPrintingPolicy(nd->getASTContext()));
    } else*/
    {
      printQualifiedName(nd, OS, createPrintingPolicy(nd->getASTContext()));
    }
  }
  return OS.str();
}

std::string rocket::common::getFullFuncName(const clang::FunctionDecl *fd,
                                            bool with_scope, bool with_parms) {
  PrintingPolicy pp = clang::PrintingPolicy(fd->getASTContext().getLangOpts());

  pp.SuppressUnwrittenScope = true;  // 忽略无名边界
  pp.FullyQualifiedName = true;

  std::string func_str;

  std::string name;
  if (with_scope) {
    llvm::raw_string_ostream OS(func_str);
    printQualifiedName(fd, OS, pp);
    OS.flush();
  } else {
    func_str = fd->getNameAsString();
  }

  if (fd->isFunctionTemplateSpecialization()) {
    func_str.append("<");
    unsigned int i = 0;
    for (; i < fd->getTemplateSpecializationArgs()->size(); ++i) {
      func_str.append(
          getFullSpecArgStr(fd->getTemplateSpecializationArgs()->get(i),
                            fd->getASTContext()) +
          ",");
    }
    if (i > 0) {
      func_str.pop_back();
    }
    func_str.append(" >");
  }

  if (with_parms) {
    func_str.append("(");
    if (!fd->parameters().empty()) {
      for (auto parm : fd->parameters()) {
        func_str.append(getFullQTypeName(parm->getType(), fd->getASTContext()) +
                        ",");
      }
      if (fd->isVariadic()) {
        func_str.append("...");
      } else {
        func_str.pop_back();
      }
    }
    func_str.append(")");
  }

  auto ft = fd->getType()->castAs<clang::FunctionType>();
  if (auto fpt = dyn_cast<FunctionProtoType>(ft)) {
    if (fpt->exceptions().size() != 0) {
      func_str.append(" throw(");
      for (auto et : fpt->exceptions()) {
        func_str.append(getFullQTypeName(et, fd->getASTContext()) + ",");
      }
      func_str.pop_back();
      func_str.append(")");
    }
  }

  // TODO: template<>前缀

  return func_str;
}

/// getFullQTypeName - 获取类型的带边界可用全名
std::string rocket::common::getFullQTypeName(const clang::QualType &qt,
                                             const clang::ASTContext &ast) {
  if (qt->isPointerType()) {
    auto pointee_type = qt->getPointeeType();
    if (pointee_type->getAsRecordDecl() &&
        pointee_type->getAsRecordDecl()->getNameAsString() == "__va_list_tag") {
      if (qt.getLocalQualifiers().empty()) {
        return "va_list";
      } else {
        return qt.getLocalQualifiers().getAsString() + " va_list";
      }
    }
  }
  string name = qt.getAsString(createPrintingPolicy(ast));
  return name;
}

void rocket::common::getFullScopeStr(const clang::NamedDecl *ND,
                                     llvm::raw_ostream &OS,
                                     const clang::PrintingPolicy &P) {
  const DeclContext *Ctx = ND->getDeclContext();

  // For ObjC methods and properties, look through categories and use the
  // interface as context.
  if (auto *MD = dyn_cast<ObjCMethodDecl>(ND))
    if (auto *ID = MD->getClassInterface()) Ctx = ID;
  if (auto *PD = dyn_cast<ObjCPropertyDecl>(ND)) {
    if (auto *MD = PD->getGetterMethodDecl())
      if (auto *ID = MD->getClassInterface()) Ctx = ID;
  }

  if (Ctx->isFunctionOrMethod()) return;

  using ContextsTy = SmallVector<const DeclContext *, 8>;
  ContextsTy Contexts;

  // Collect named contexts.
  while (Ctx) {
    if (isa<NamedDecl>(Ctx)) Contexts.push_back(Ctx);
    Ctx = Ctx->getParent();
  }

  for (const DeclContext *DC : llvm::reverse(Contexts)) {
    if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
      const auto *PSpec =
          dyn_cast<ClassTemplatePartialSpecializationDecl>(Spec);
      if (PSpec && PSpec->getTemplateArgsAsWritten()) {
        OS << PSpec->getName();
        const auto &TemplateArgs =
            PSpec->getTemplateArgsAsWritten()->arguments();
        printTemplateArgumentList(OS, TemplateArgs, P,
                                  PSpec->getTemplateParameters());
      } else {
        OS << Spec->getName();
        const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
        printTemplateArgumentList(OS, TemplateArgs.asArray(), P);
      }
    } else if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) {
      if (P.SuppressUnwrittenScope &&
          (ND->isAnonymousNamespace() || ND->isInline()))
        continue;
      if (ND->isAnonymousNamespace()) {
        OS << (P.MSVCFormatting ? "`anonymous namespace\'"
                                : "(anonymous namespace)");
      } else
        OS << *ND;
    } else if (const auto *RD = dyn_cast<RecordDecl>(DC)) {
      if (!RD->getIdentifier()) {
        OS << "(anonymous " << RD->getKindName() << ')';
      } else if (auto TD = RD->getDescribedTemplate()) {
        // FIXME: 暂时的边界名获取方案
        OS << QualType(RD->getTypeForDecl(), 0).getAsString(P);
      } else {
        OS << RD->getName();
      }
    } else if (const auto *FD = dyn_cast<FunctionDecl>(DC)) {
      const FunctionProtoType *FT = nullptr;
      if (FD->hasWrittenPrototype())
        FT = dyn_cast<FunctionProtoType>(FD->getType()->castAs<FunctionType>());

      OS << *FD << '(';
      if (FT) {
        unsigned NumParams = FD->getNumParams();
        for (unsigned i = 0; i < NumParams; ++i) {
          if (i) OS << ", ";
          OS << FD->getParamDecl(i)->getType().stream(P);
        }

        if (FT->isVariadic()) {
          if (NumParams > 0) OS << ", ";
          OS << "...";
        }
      }
      OS << ')';
    } else if (const auto *ED = dyn_cast<EnumDecl>(DC)) {
      // C++ [dcl.enum]p10: Each enum-name and each unscoped
      // enumerator is declared in the scope that immediately contains
      // the enum-specifier. Each scoped enumerator is declared in the
      // scope of the enumeration.
      // For the case of unscoped enumerator, do not include in the qualified
      // name any information about its enum enclosing scope, as its visibility
      // is global.
      if (ED->isScoped())
        OS << *ED;
      else
        continue;
    } else {
      OS << *cast<NamedDecl>(DC);
    }
    OS << "::";
  }
}

std::string rocket::common::getFullScopeStr(const clang::NamedDecl *ND) {
  std::string str;
  llvm::raw_string_ostream OS(str);
  PrintingPolicy pp(ND->getASTContext().getLangOpts());
  pp.FullyQualifiedName = 0;
  getFullScopeStr(ND, OS, pp);
  return OS.str();
}

std::string rocket::common::getFullDeclStr(const Decl *decl) {
  std::string tmp;
  llvm::raw_string_ostream OS(tmp);
  decl->print(OS, createPrintingPolicy(decl->getASTContext().getLangOpts()));
  return OS.str();
}

std::string rocket::common::getFullStmtStr(const Stmt *st,
                                           const ASTContext &ast) {
  if (st) {
    bool invalid;
    std::string src;
    src = (std::string)clang::Lexer::getSourceText(
        CharSourceRange(st->getSourceRange(), true), ast.getSourceManager(),
        ast.getLangOpts(), &invalid);

    if (invalid) {
      llvm::raw_string_ostream rso(src);
      st->printPretty(rso, nullptr, ast.getLangOpts());
      return rso.str();
    } else {
      return src;
    }
  } else {
    return "";
  }
}

std::string rocket::common::getFullSpecArgStr(const TemplateArgument &ta,
                                              const ASTContext &ast) {
  std::string e;
  llvm::raw_string_ostream OS(e);
#if LLVM_VERSION_MAJOR > 18
  ta.dump(OS, ast);
#else
  ta.dump(OS);
#endif
  return OS.str();
}

std::string rocket::common::makeVarDecl(const std::string &type_str,
                                        const std::string &var_name) {
  size_t pos = type_str.find(")");
  if (pos != type_str.npos) {
    return type_str.substr(0, pos) + " " + var_name + type_str.substr(pos);
  }
  pos = type_str.find("[");
  if (pos != type_str.npos) {
    return type_str.substr(0, pos) + " " + var_name + type_str.substr(pos);
  }
  return type_str + " " + var_name;
}

std::string rocket::common::makeVarDecl(const QualType &type,
                                        std::string var_name,
                                        const ASTContext &ast, bool allow_suger,
                                        bool is_top) {
  if (type.isNull()) return "";

  if (auto attr_type = type->getAs<AttributedType>()) {
    if (attr_type->getAttrKind() == attr::StdCall) {
      var_name = "(__stdcall " + var_name + ")";
    }
  }

  if (ast.getLangOpts().CPlusPlus && type->getAs<ElaboratedType>()) {
    return makeVarDecl(type.getDesugaredType(ast), var_name, ast, allow_suger,
                       is_top);
  } else if (type->isMemberPointerType()) {
    auto memptr_type = type->getAs<MemberPointerType>();
    assert(memptr_type);
    string var_name_expr =
        common::getFullQTypeName(QualType(memptr_type->getClass(), 0), ast) +
        "::*" + var_name;

    if (type->isMemberFunctionPointerType()) {
      var_name_expr = "(" + var_name_expr + ")";
    }

    return makeVarDecl(memptr_type->getPointeeType(), var_name_expr, ast,
                       allow_suger, false);
  } else if (type->isLValueReferenceType()) {
    return makeVarDecl(type->getPointeeType(), "&" + var_name, ast, allow_suger,
                       false);
  } else if (type->isRValueReferenceType()) {
    return makeVarDecl(type->getPointeeType(), "&&" + var_name, ast,
                       allow_suger, false);
  } else if (auto typedef_type = type->getAs<TypedefType>()) {
    auto desugar_type = type.getDesugaredType(ast);
    if (auto rd = desugar_type->getAsRecordDecl()) {
      if (isAnonymous(rd)) {
        std::string type_name = getFullQTypeName(type, ast);
        if (var_name.empty()) return type_name;
        return type_name + " " + var_name;
      }
    }

    if (desugar_type->isDependentType() && allow_suger) {
      string type_name = typedef_type->getDecl()->getNameAsString();
      if (type.hasQualifiers()) {
        return type.getQualifiers().getAsString(ast.getLangOpts()) + " " +
               type_name + " " + var_name;
      } else {
        return type_name + " " + var_name;
      }
    }

    return makeVarDecl(desugar_type, var_name, ast, allow_suger, is_top);
  } else if (type->isArrayType()) {
    const ArrayType *array_type = type->getAsArrayTypeUnsafe();
    const QualType element_type = array_type->getElementType();

    std::string var_name_opt = is_top ? var_name : "(" + var_name + ")";
    const clang::ConstantArrayType *cat =
        dyn_cast<clang::ConstantArrayType>(array_type);
    return makeVarDecl(
        element_type,
        (type.getLocalQualifiers().empty()
             ? var_name_opt
             : type.getLocalQualifiers().getAsString() + " " + var_name_opt) +
            "[" +
            (cat ? std::to_string(cat->getSize().getZExtValue())
                 : std::string("")) +
            "]",
        ast, allow_suger, false);
  } else if (type->isFunctionPointerType()) {
    return makeVarDecl(
        type->getPointeeType(),
        "(*" +
            (type.getLocalQualifiers().empty()
                 ? var_name
                 : type.getLocalQualifiers().getAsString() + " " + var_name) +
            ")",
        ast, allow_suger, false);
  } else if (type->isPointerType()) {
    auto pointee_type = type->getPointeeType();
    if (pointee_type->getAsRecordDecl() &&
        pointee_type->getAsRecordDecl()->getNameAsString() == "__va_list_tag") {
      if (type.getLocalQualifiers().empty()) {
        return "va_list " + var_name;
      } else {
        return type.getLocalQualifiers().getAsString() + " va_list " + var_name;
      }
    }

    string var_name_opt =
        type.getLocalQualifiers().empty()
            ? var_name
            : type.getLocalQualifiers().getAsString() + " " + var_name;
    return makeVarDecl(type->getPointeeType(), "*" + var_name_opt, ast,
                       allow_suger, false);
  } else if (auto *function_type = type->getAs<FunctionType>()) {
    return makeFuncTypeCopy(function_type, var_name, ast);
  } /*else if (auto mem_func_type = type->getAs<MemberPointerType>()) {
    // TODO:
  }*/
  else if (type->getAs<TemplateSpecializationType>() &&
           type->isDependentType()) {
    auto temp_spec_type = type->getAs<TemplateSpecializationType>();
    string type_name = getFullNDeclName(
        temp_spec_type->getTemplateName().getAsTemplateDecl(), false);
#if LLVM_VERSION_MAJOR < 16
    if (temp_spec_type->getNumArgs() > 0) {
      type_name.append("<");

      for (size_t i = 0; i < temp_spec_type->getNumArgs(); ++i) {
        auto &targ = temp_spec_type->getArg(i);
        if (targ.getKind() == TemplateArgument::ArgKind::Type) {
          type_name.append(
              makeVarDecl(targ.getAsType(), "", ast, allow_suger, true));
        } else {
          string s;
          llvm::raw_string_ostream OS(s);
          targ.dump(OS);
          type_name.append(OS.str());
        }
        type_name.append(",");
      }
      type_name.pop_back();
      type_name.append(">");
    }
#else
    if (temp_spec_type->template_arguments().size() > 0) {
      type_name.append("<");

      for (size_t i = 0; i < temp_spec_type->template_arguments().size(); ++i) {
        auto &targ = temp_spec_type->template_arguments()[i];
        if (targ.getKind() == TemplateArgument::ArgKind::Type) {
          type_name.append(
              makeVarDecl(targ.getAsType(), "", ast, allow_suger, true));
        } else {
          string s;
          llvm::raw_string_ostream OS(s);
#if LLVM_VERSION_MAJOR > 18
          targ.dump(OS, ast);
#else
          targ.dump(OS);
#endif
          type_name.append(OS.str());
        }
        type_name.append(",");
      }
      type_name.pop_back();
      type_name.append(">");
    }
#endif

    return type.getLocalQualifiers().getAsString() + " " + type_name + " " +
           var_name;
  } else {
    const TagDecl *decl = type->getAsTagDecl();
    if (decl) {
      if (isAnonymous(decl)) {
        // TODO:带边界名的变量
        string decl_str = type.getLocalQualifiers().getAsString() + " " +
                          getFullDeclStr(decl) + " " + var_name;
        return decl_str;
      }
    }

    if (type->isDependentType()) {
      string type_name = type.getAsString();
      return type_name + " " + var_name;
    }

    // 当该类型为模板特化时会丢失命名空间，因此重新构建类型
    if (auto cxxrd = type->getAsCXXRecordDecl()) {
      if (type.hasQualifiers()) {
        string type_name =
            getFullQTypeName(QualType(cxxrd->getTypeForDecl(), 0), ast);
        return type.getQualifiers().getAsString(ast.getLangOpts()) + " " +
               type_name + " " + var_name;
      } else {
        string type_name =
            getFullQTypeName(QualType(cxxrd->getTypeForDecl(), 0), ast);
        return type_name + " " + var_name;
      }
    } else if (auto crd = type->getAsRecordDecl()) {
      if (crd->getDefinition()) {
        auto context = crd->getDeclContext();
        while (context && context != ast.getTranslationUnitDecl()) {
          if (isa<FunctionDecl>(context)) {
            string type_name;
            if (type->isUnionType()) {
              type_name += "union{";
            } else if (type->isStructureType()) {
              type_name += "struct{";
            } else if (type->isClassType()) {
              type_name += "class{";
            }
            const RecordDecl *record_decl = dyn_cast<RecordDecl>(decl);
            assert(record_decl != NULL);
            // TODO: Add C++ embedded types.
            for (auto field : record_decl->fields()) {
              type_name
                  .append(makeVarDecl(field->getType(),
                                      field->getNameAsString(), ast))
                  .append(";");
            }
            type_name += "}";

            return type.getLocalQualifiers().getAsString() + " " + type_name +
                   " " + var_name;
          }
          context = context->getParent();
        }
      }
    }

    return getFullQTypeName(type, ast) + " " + var_name;
  }
}

static std::string makeTempParmDecl(const NamedDecl *tp) {
  assert(tp->isTemplateParameter());

  std::string str = "";
  if (const TemplateTypeParmDecl *ttpd = dyn_cast<TemplateTypeParmDecl>(tp)) {
    str = "typename " + ttpd->getNameAsString();
  } else if (const NonTypeTemplateParmDecl *nttpd =
                 dyn_cast<NonTypeTemplateParmDecl>(tp)) {
    str = makeVarDecl(nttpd->getType(), nttpd->getNameAsString(),
                      nttpd->getASTContext());
  } else if (const TemplateTemplateParmDecl *ttpd =
                 dyn_cast<TemplateTemplateParmDecl>(tp)) {
    str = makeTemplateParmList(ttpd->getTemplateParameters()) + " class " +
          ttpd->getNameAsString();
  } else {
    throw std::runtime_error("not supported TemplateParamDecl");
  }

  if (tp->isTemplateParameterPack()) str.append(" ...");

  return str;
}

string rocket::common::makeTemplateParmList(
    const TemplateParameterList *parm_list) {
  string temp_pref = "template<";
  for (auto parm : parm_list->asArray()) {
    temp_pref.append(makeTempParmDecl(parm) + ",");
  }
  if (parm_list->size() > 0) {
    temp_pref.pop_back();
  }
  temp_pref.append(" >");

  return temp_pref;
}

std::string rocket::common::makeFuncTypeCopy(
    const FunctionType *func_type, std::string func_name, const ASTContext &ast,
    const map<size_t, string> &param_names) {
  if (const FunctionProtoType *function_proto_type =
          dyn_cast<FunctionProtoType>(func_type)) {
    func_name.append("(");
    size_t i;
    for (i = 0; i < function_proto_type->getNumParams(); ++i) {
      auto param_name_it = param_names.find(i);
      string param_name;
      if (param_name_it != param_names.end()) {
        param_name = param_name_it->second;
      } else {
        param_name = "_" + std::to_string(i);
      }

      func_name.append(
          makeVarDecl(function_proto_type->getParamType(i), param_name, ast));
      if (i < function_proto_type->getNumParams() - 1) {
        func_name.append(", ");
      }
    }
    if (function_proto_type->isVariadic()) {
      func_name.append(", ...)");
    } else {
      func_name.append(")");
    }
  } else {
    func_name.append("()");
  }

  // FIXEME:构造函数是否可能在此出现?
  func_name = makeVarDecl(func_type->getReturnType(), func_name, ast);

  // CPP - Dynamic exception specification
  // TODO: 试作，准确性代测试
  if (auto fpt = dyn_cast<FunctionProtoType>(func_type)) {
    if (fpt->exceptions().size() != 0) {
      func_name.append(" throw(");
      for (auto et : fpt->exceptions()) {
        func_name.append(getFullQTypeName(et, ast) + ",");
      }
      func_name.pop_back();
      func_name.append(")");
    }
  }

  return func_name;
}

static bool isThisFuncDeclInstantiatedFromAFriendDefinition(
    const FunctionDecl *func) {
  if (!func->getFriendObjectKind()) return false;

  // Check for a friend function instantiated from a friend function
  // definition in a templated class.
  if (const FunctionDecl *InstantiatedFrom =
          func->getInstantiatedFromMemberFunction())
    return InstantiatedFrom->getFriendObjectKind() &&
           InstantiatedFrom->isThisDeclarationADefinition();

  // Check for a friend function template instantiated from a friend
  // function template definition in a templated class.
  if (const FunctionTemplateDecl *Template =
          func->getDescribedFunctionTemplate()) {
    if (const FunctionTemplateDecl *InstantiatedFrom =
            Template->getInstantiatedFromMemberTemplate())
      return InstantiatedFrom->getFriendObjectKind() &&
             InstantiatedFrom->isThisDeclarationADefinition();
  }

  return func->getFriendObjectKind();
}

std::string rocket::common::getOverloadedOperatorName(
    OverloadedOperatorKind ook) {
  switch (ook) {
    case OO_None:
      return "";
    case NUM_OVERLOADED_OPERATORS:
      return "NUM_OVERLOADED";
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
  case OO_##Name:                                                             \
    return "Name";
#include "clang/Basic/OperatorKinds.def"
  }

  return "";
}

std::string rocket::common::getFullTempSpecArgsList(
    clang::ArrayRef<TemplateArgument> Args, const PrintingPolicy &Policy) {
  std::string str;
  llvm::raw_string_ostream OS(str);
  printTemplateArgumentList(OS, Args, Policy);
  return OS.str();
}

std::string rocket::common::getFullTempSpecArgsList(const FunctionDecl *fd) {
  if (fd->isFunctionTemplateSpecialization()) {
    return getFullTempSpecArgsList(
        fd->getTemplateSpecializationArgs()->asArray(),
        createPrintingPolicy(fd->getASTContext().getLangOpts()));
  } else {
    return "";
  }
}

std::string rocket::common::getFullTempSpecArgsList(
    const CXXRecordDecl *cxxrd) {
  if (auto ctsd = dyn_cast<clang::ClassTemplateSpecializationDecl>(cxxrd)) {
    return getFullTempSpecArgsList(
        ctsd->getTemplateArgs().asArray(),
        createPrintingPolicy(ctsd->getASTContext().getLangOpts()));
  } else {
    return "";
  }
}

string rocket::common::getFullTempParamsSpecList(
    const TemplateParameterList &Params, const PrintingPolicy &) {
  auto param_decls = Params.asArray();
  if (param_decls.empty()) return "";

  string str = "<";
  for (auto pd : param_decls) {
    str.append(pd->getNameAsString() + ",");
  }
  str.pop_back();
  str.append(" >");

  return str;
}

string rocket::common::makeFuncDeclCopy(
    const FunctionDecl *func_decl, const string &fname,
    // 参数
    const std::map<size_t, string> &param_names, bool require_params_name_force,
    bool require_params_init,
    // first decl flag
    bool is_first_decl) {
  if (!func_decl) return "";

  auto &ast = func_decl->getASTContext();

  std::string func_decl_ret =
      !fname.empty()
          ? fname
          : (is_first_decl ? func_decl->getNameAsString()
                           : common::getFullNDeclName(func_decl, false));

  {  // 模板特化"实参"
    string template_args = "";
    bool should_add = false;
    if (func_decl->isFunctionTemplateSpecialization() &&
        !isa<CXXConstructorDecl>(func_decl)) {
      should_add = true;

      // NOTE: operator< 时如果不加空格会变成<<导致错误
      if (func_decl->getTemplateSpecializationArgs()) {
        template_args.append(" <");
        for (auto &tag :
             func_decl->getTemplateSpecializationArgs()->asArray()) {
          if (tag.getKind() == TemplateArgument::ArgKind::Pack) {
            should_add = false;
            break;
          }
          template_args.append(getFullSpecArgStr(tag, ast) + ",");
        }
        if (func_decl->getTemplateSpecializationArgs()->size() > 0) {
          template_args.pop_back();
        }
        template_args.append(" >");
      }
    }
    if (should_add) func_decl_ret.append(template_args);
  }

  {  // 函数声明"形参"
    func_decl_ret.append("(");
    size_t i;
    for (i = 0; i < func_decl->getNumParams(); ++i) {
      string pname = "";
      auto param_name_it = param_names.find(i);
      auto param_decl = func_decl->getParamDecl(i);
      if (param_name_it != param_names.end()) {
        pname = param_name_it->second;
      } else {
        pname = param_decl->getNameAsString();
        if (pname.empty() && require_params_name_force) {
          pname = "_" + std::to_string(i);
        }
      }

      func_decl_ret.append(makeVarDecl(func_decl->getParamDecl(i)->getType(),
                                       pname, ast, is_first_decl));
      if (require_params_init) {
        if (auto pinit = param_decl->getInit()) {
          func_decl_ret.append("=" + getFullStmtStr(pinit, ast));
        }
      }
      if (i < func_decl->getNumParams() - 1) {
        func_decl_ret.append(", ");
      }
    }

    if (func_decl->isVariadic()) {
      func_decl_ret.append(", ...)");
    } else {
      func_decl_ret.append(")");
    }
  }

  do {  // 函数返回"类型"
    if (auto method_decl = dyn_cast<CXXMethodDecl>(func_decl)) {
      if (isa<CXXConstructorDecl>(func_decl) ||
          isa<CXXDestructorDecl>(func_decl) ||
          isa<CXXConversionDecl>(func_decl)) {
        if (func_decl->getNameAsString() == fname ||
            getFullNDeclName(func_decl, false) == fname ||
            method_decl->getParent()->getNameAsString() == fname) {
          break;
        }
      }
    }

    func_decl_ret = makeVarDecl(func_decl->getReturnType(), func_decl_ret,
                                func_decl->getASTContext(), is_first_decl);
  } while (0);

  {  // 补充声明"修饰词"
    auto ft = func_decl->getType()->castAs<clang::FunctionType>();
    if (auto fpt = dyn_cast<FunctionProtoType>(ft)) {
      if (fpt->exceptions().size() != 0) {
        func_decl_ret.append(" throw(");
        for (auto et : fpt->exceptions()) {
          func_decl_ret.append(getFullQTypeName(et, ast) + ",");
        }
        func_decl_ret.pop_back();
        func_decl_ret.append(")");
      }
    }

    if (is_first_decl) {
      if (func_decl->getStorageClass() == SC_Static) {
        func_decl_ret = "static " + func_decl_ret;
      } else if (func_decl->isVirtualAsWritten()) {
        func_decl_ret = "virtual " + func_decl_ret;
      }
    }

    if (isa<CXXMethodDecl>(func_decl) &&
        dyn_cast<CXXMethodDecl>(func_decl)->isConst()) {
      func_decl_ret.append(" const");
    }

    if (is_first_decl && isa<CXXConstructorDecl>(func_decl) &&
        dyn_cast<CXXConstructorDecl>(func_decl)->isExplicit() &&
        (fname == func_decl->getNameAsString() ||
         fname == common::getFullNDeclName(func_decl))) {
      func_decl_ret = "explicit " + func_decl_ret;
    }

    if (is_first_decl && isThisFuncDeclInstantiatedFromAFriendDefinition(
                             func_decl->getFirstDecl())) {
      func_decl_ret = "friend " + func_decl_ret;
    }
  }

  {  // 模板实参/形参列表
    if (!is_first_decl && (func_decl->isFunctionTemplateSpecialization() ||
                           isContextSpecDecl(func_decl))) {
      std::string temp_pref = "";
      auto fd = func_decl;

      if (func_decl->isFunctionTemplateSpecialization()) {
        temp_pref = "template<> " + temp_pref;
      }

      if (!is_first_decl) {
        auto tud = fd->getDeclContext();
        while (tud && !isa<TranslationUnitDecl>(tud)) {
          if (auto cxxrd = dyn_cast<ClassTemplateSpecializationDecl>(tud)) {
            temp_pref = "template<> " + temp_pref;
          }
          tud = tud->getParent();
        }
      }

      return temp_pref + " " + func_decl_ret;
    } else if (func_decl->isTemplated()) {
      auto fd = func_decl;

      FunctionTemplateDecl *ftd = nullptr;
      std::string temp_pref = "";

      if (fd->isTemplated()) {
        ftd = fd->getPrimaryTemplate() ? fd->getPrimaryTemplate()
                                       : fd->getDescribedFunctionTemplate();
      } else if (auto msi = func_decl->getMemberSpecializationInfo()) {
        fd = dyn_cast<FunctionDecl>(msi->getInstantiatedFrom());
        assert(fd);
        ftd = fd->getDescribedFunctionTemplate();
      }

      if (ftd) {
        temp_pref.append("template<");
        for (auto tp : ftd->getTemplateParameters()->asArray()) {
          temp_pref.append(makeTempParmDecl(tp) + ",");
        }
        temp_pref.pop_back();
        temp_pref.append(" >");
      }

      if (!is_first_decl) {
        auto tud = func_decl->getASTContext().getTranslationUnitDecl();
        for (auto fc = fd->getFirstDecl()->getParent(); fc != tud;
             fc = fc->getParent()) {
          if (auto cxxrd = dyn_cast<CXXRecordDecl>(fc)) {
            // TODO: 可能不止于模板类
            if (cxxrd->isTemplated()) {
              // FIXME: rtd可能为空
              auto rtd = cxxrd->getDescribedClassTemplate();
              if (rtd) {
                if (auto tparams = rtd->getTemplateParameters()) {
                  std::string ctd_pref = "";
                  ctd_pref.append("template<");
                  for (auto tp : tparams->asArray()) {
                    ctd_pref.append(makeTempParmDecl(tp) + ",");
                  }
                  ctd_pref.pop_back();
                  ctd_pref.append(" >");

                  temp_pref = ctd_pref + " " + temp_pref;
                }
              }
            }
          }
        }
      }

      return temp_pref + " " + func_decl_ret;
    }
  }

  return func_decl_ret;
}

string rocket::common::makeFuncFstDeclCopy(
    const FunctionDecl *func_decl, string fname,
    const std::map<size_t, string> &param_names) {
  string copy = makeFuncDeclCopy(func_decl, fname, param_names,
                                 /*require_params_name_force = */ true,
                                 /*require_params_init = */ true,
                                 /*is_first_decl = */ true);
  return copy;
}

string rocket::common::makeFuncDefDeclCopy(
    const FunctionDecl *func_decl, string fname,
    const std::map<size_t, string> &param_names) {
  return makeFuncDeclCopy(func_decl, fname, param_names,
                          /*require_params_name_force = */ true,
                          /*require_params_init = */ false,
                          /*is_first_decl = */ false);
}

void rocket::common::removeNullValues(nlohmann::json &j) {
  if (j.is_object()) {
    // 复制一份当前对象的所有key，因为在迭代时可能会删除元素
    std::vector<std::string> keys;
    for (auto &element : j.items()) {
      keys.push_back(element.key());
    }

    // 遍历当前对象的所有key
    for (const auto &key : keys) {
      if (j[key].is_null()) {
        // 删除value为null的key
        j.erase(key);
      } else {
        // 递归处理非null值的子对象
        removeNullValues(j[key]);
      }
    }
  } else if (j.is_array()) {
    // 遍历数组的所有元素
    for (auto it = j.begin(); it != j.end();) {
      if (it->is_null()) {
        // 删除value为null的元素
        it = j.erase(it);
      } else {
        // 递归处理非null值的数组元素
        removeNullValues(*it);
        ++it;
      }
    }
  }
}
